//////////////////////////////////////////
// FLOCK CLASS							//
//////////////////////////////////////////
/**
 * Manages tracking, updating, and killing biods, emitters, predators, and their bodies.
 */

var g_flock = null;

var g_mouseEmitter = null;
var g_mouseIsDown = false;
var g_pIsPressed = false;
var g_kIsPressed = false;
var g_lIsPressed = false;
var g_bIsPressed = false;
var g_rIsPressed = false;
var g_mouseVec = new Vector(0, 0);
import { BiodBody } from "./BiodBody.js";
import { Vector } from "./Vector.js";

class Flock {
    constructor(svg) {
        this.flock = [];
        this.bodies = [];
        this.emitters = [];
        this.emitterBodies = [];
        this.predators = [];
        this.predatorBodies = [];
        this.svg = svg;
    }

    addBiod(biod) {
        this.flock.push(biod);
        this.bodies.push(new BiodBody(this.svg, biod, false));
    }

    addPredator(predator) {
        this.predators.push(predator);
        this.predatorBodies.push(new BiodBody(this.svg, predator, true));
    }

    addEmitter(emitter) {
        this.emitters.push(emitter);
        this.emitterBodies.push(new EmitterBody(this.svg, emitter));
    }

    /**
     * Cleans up SVG elements for everything in this flock.
     */
    die() {
        [...this.bodies, ...this.emitterBodies, ...this.predatorBodies].forEach(
            (i) => i.die()
        );
    }

    /**
     * Updates our simulation.
     *
     * - Performs user input handling (keyboard).
     * - Kills biods who are being eaten.
     * - Updates emitters.
     * - Updates predators.
     * - Updates biods.
     */
    update(g_keysDown = []) {
        ////////////////////////////
        //Handle user input.
        ///////////////////////////
        //Add a predator.
        if (80 in g_keysDown) {
            //p adds a predator at a random point.
            if (!g_pIsPressed) {
                g_pIsPressed = true;
                var newPredator = new Predator(
                    new Vector(BoundedRandom(0, 800), BoundedRandom(0, 600)),
                    10,
                    12,
                    10,
                    200,
                    40000,
                    200,
                    new Vector(800, 600)
                );
                g_flock.addPredator(newPredator);
            }
        } else {
            g_pIsPressed = false;
        }

        //Add an attractive emitter.
        if (75 in g_keysDown) {
            //k adds a permanent attractor at mouse point.
            if (!g_kIsPressed) {
                g_kIsPressed = true;
                var newEmitter = new Emitter(
                    g_mouseVec,
                    BoundedRandom(3000, 6000),
                    BoundedRandom(25, 150),
                    "linear",
                    false
                );
                g_flock.addEmitter(newEmitter);
            }
        } else {
            g_kIsPressed = false;
        }

        //Add a repulsive emitter.
        if (76 in g_keysDown) {
            //k adds a permanent attractor at mouse point.
            if (!g_lIsPressed) {
                g_lIsPressed = true;
                var newEmitter = new Emitter(
                    g_mouseVec,
                    BoundedRandom(1000, 4000),
                    BoundedRandom(25, 150),
                    "linear",
                    true
                );
                g_flock.addEmitter(newEmitter);
            }
        } else {
            g_lIsPressed = false;
        }

        //Add a biod
        if (66 in g_keysDown) {
            //b adds a biod at mouse point.
            if (!g_bIsPressed) {
                g_bIsPressed = true;
                var newBiod = new Biod(
                    g_mouseVec.add(
                        new Vector(
                            BoundedRandom(-10, 10),
                            BoundedRandom(-10, 10)
                        )
                    ),
                    3,
                    10,
                    7,
                    40,
                    200,
                    20,
                    new Vector(800, 600)
                );
                g_flock.addBiod(newBiod);
            }
        } else {
            g_bIsPressed = false;
        }

        //Reset the simulation.
        if (82 in g_keysDown) {
            //r resets the sim.
            if (!g_rIsPressed) {
                g_rIsPressed = true;
                resetSim();
            }
        } else {
            g_rIsPressed = false;
        }

        ///////////////////////////
        //Update sim.
        ///////////////////////////
        //Kill off biods that have been eaten!
        for (var i = 0; i < this.flock.length; i++) {
            var isDead = false;

            for (var j = 0; j < this.predators.length; j++) {
                if (
                    this.flock[i].position.getDistance(
                        this.predators[j].position
                    ) < Math.max(this.flock[i].radius, this.predators[j].radius)
                ) {
                    this.flock.splice(i, 1);
                    this.bodies[i].die();
                    this.bodies.splice(i, 1);

                    isDead = true;
                    break;
                }
            }

            if (isDead) break;
        }

        //Update emitters.
        for (var i = 0; i < this.emitters.length; i++)
            this.emitters[i].update(this.flock);

        //Update possible mouse emitter.
        if (g_mouseEmitter != null && g_mouseIsDown) {
            g_mouseEmitter.repel = 16 in g_keysDown ? true : false;
            g_mouseEmitter.update(this.flock);
        }

        //Update predators.
        var newPredHeadings = this.predators.map((i) =>
            i.calculateNewHeading(this.flock)
        );

        //Move the biods.
        for (var i = 0; i < this.predators.length; i++)
            this.predators[i].move(newPredHeadings[i], this.flock);

        //Calculate new headings for all biods within the flock.
        var newHeadings = this.flock.map((i) =>
            i.calculateNewHeading(this.flock)
        );

        //Move the biods.
        for (var i = 0; i < this.flock.length; i++)
            this.flock[i].move(newHeadings[i]);

        //Update the bodies.
        [...this.bodies, ...this.emitterBodies, ...this.predatorBodies].forEach(
            (i) => i.update()
        );
    }
}

export { Flock };
